package com.joinway.framework.admin.core.service.file;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.joinway.framework.admin.bean.form.ExportForm;
import com.joinway.framework.admin.bean.view.ExportView;
import com.joinway.framework.admin.bean.view.ImportView;
import com.joinway.framework.admin.core.bean.DataRecord;
import com.joinway.framework.admin.core.bean.FileImportContext;
import com.joinway.framework.admin.core.service.table.ITableService;
import com.joinway.framework.admin.core.service.table.TableServiceFactory;
import com.joinway.framework.bean.constant.ErrorCodeConstants;
import com.joinway.framework.bean.exception.InternalException;
import com.joinway.framework.bean.logging.annotation.InputLog;
import com.joinway.framework.core.plugin.PluginManager;
import com.joinway.framework.data.jdbc.repository.TableRepository;
import com.joinway.framework.extension.groovy.DomainUtils;


@Service
public class FileService {
	
	private final static Logger log = LoggerFactory.getLogger(FileService.class);
	
	final static String DEFAULT_TYPE = "xls";
	final static String COLUMN_DELIMITER = ";"; 
	final static String FIELD_DELIMITER = ","; 
	final static String UPLOAD_DIR = "upload";
	
	@Autowired protected TableRepository repository;
	
	@Autowired protected List<FileProcessor> fileProcessors;
	
	public ExportView export(ExportForm form) throws Exception {
		ExportView view = new ExportView();
		
		String type = StringUtils.isBlank(form.getType()) ? FileConstants.FileType.Excel2003 : StringUtils.trimToEmpty(form.getType());
		
		String[] pairs = StringUtils.split(StringUtils.trimToEmpty(form.getColumns()), COLUMN_DELIMITER);
		
		/*
		 * construct column headers
		 */
		// key - field name, value - display name
		Map<String, String> columns = new LinkedHashMap<>();
		for(String p : pairs){
			String[] kv = StringUtils.split(p, FIELD_DELIMITER);
			
			String columnName = StringUtils.trimToEmpty(kv[0]);
			if(kv.length > 1){
				columns.put(columnName, StringUtils.trimToEmpty(kv[1]));
			}else{
				columns.put(columnName, DomainUtils.convertToDBName(columnName));
			}
		}
		
		String tableName = StringUtils.trimToEmpty(form.getTable());
		
		/*
		 * query search result
		 */
		
		ITableService tableService = TableServiceFactory.getInstance(form.getTable());
		
		DataRecord record = tableService.find(tableName, form.getQuery(), null, null, null);
		
		log.info("prepare to export table {}", tableName);
		
		FileProcessor processor = getFileProcessor(type, form.getTable());
								
		String url = processor.export(form.getFileName(), columns, record.getDomains(), form.getPort());
		
		view.setUrl(url);
		
		return view;
	}
	
	@Transactional(rollbackFor=Throwable.class)
	@InputLog
	public ImportView imports(File file, String table, String columnMap) throws Exception {
		ImportView view = new ImportView();
		
		String type = FilenameUtils.getExtension(file.getName());
		
		FileProcessor processor = getFileProcessor(type, table);
		
		if(processor != null){
			FileImportContext context = processor.imports(file, table, columnMap);
			log.info("{} rows was imported", context.getImportedCount());
			log.info("{} rows was ignored", context.getIgnoredCount());
			
			view.setImportedCount(context.getImportedCount());
			view.setIgnoredCount(context.getIgnoredCount());
			view.setMessage(context.getMessage());
		}else{
			throw new InternalException(ErrorCodeConstants.INVALID_FILE, ErrorCodeConstants.INVALID_DESC);
		}
		
		return view;
	}
	
	protected FileProcessor getFileProcessor(String type, String table){
		List<FileProcessor> processors = new ArrayList<>();
		
		// 获得导出/导入相应格式的processor
		for(FileProcessor fp : fileProcessors){
			if(fp.getFileType().equalsIgnoreCase(type)){
				processors.add(fp);
			}
		}
		
		List<FileProcessor> customizedTargets = new ArrayList<>();
		for(FileProcessor fp : processors){
			if(StringUtils.isNotBlank(table) && table.equals(fp.getTargetTable())){
				customizedTargets.add(fp);
			}
		}
		
		FileProcessor target = null;
		
		if(!CollectionUtils.isEmpty(customizedTargets)){
			target = PluginManager.getInstance(customizedTargets);
		}else{
			List<FileProcessor> defaultProcessors = new ArrayList<>();
			for(FileProcessor p : processors){
				if(StringUtils.isBlank(p.getTargetTable())){
					defaultProcessors.add(p);
				}
			}
			target = PluginManager.getInstance(defaultProcessors);
		}
		
		return target;
	}
}



